package com.youlian.cloud.core.intercept;

import com.youlian.cloud.core.bean.ExceptionHandle;
import com.youlian.cloud.core.exception.CheckException;
import com.youlian.cloud.core.util.ObjectUtils;
import com.youlian.cloud.core.util.StringUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.env.Environment;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;

/**
 * 自定义代码检测，是否符合规范
 * @author liuhx
 * @create 2019/08/01 17:33
 * @email liuhx@elab-plus.com
 **/
@Slf4j
public class CheckAnnotationProcess implements BeanPostProcessor, BeanFactoryPostProcessor {

    private ConfigurableListableBeanFactory beanFactory;

    private Environment environment;
    private boolean isException = false;
    /*排除不包含的包名*/
    private String excludePackage;

    public CheckAnnotationProcess(Environment environment) {
        this.environment = environment;
        this.isException = ObjectUtils.isNotEmpty(environment.getProperty("youlian.isException")) ? Boolean.parseBoolean(environment.getProperty("youlian.isException")): false;
        this.excludePackage = environment.getProperty("youlian.excludePackage");
    }

    public void setException(boolean exception) {
        isException = exception;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        String[] checkPackageList = excludePackage.split(",");
        if (checkPackageList.length > 0) {
            String exclude = "com.elab.marketing.auth.dao";
            String proxyName = "com.sun.proxy";
            if (AopUtils.isAopProxy(bean)) {
                Class<?> targetClass = AopUtils.getTargetClass(bean);
                String name = targetClass.getName();


                for(String singlePackage : checkPackageList) {
                    if (!name.startsWith(singlePackage) && !name.startsWith(proxyName)) {
                        Method[] declaredMethods = targetClass.getDeclaredMethods();
                        for (int i = 0; i < declaredMethods.length; i++) {
                            Method declaredMethod = declaredMethods[i];
                            String author = "";
                            Transactional annotation = declaredMethod.getAnnotation(Transactional.class);
                            ApiOperation apiOperation = declaredMethod.getAnnotation(ApiOperation.class);
                            if (apiOperation != null && StringUtils.isNotEmpty(apiOperation.nickname())) {
                                author = apiOperation.nickname();
                            }
                            if (annotation != null || apiOperation != null) {
                                ExceptionHandle exceptionHandle = declaredMethod.getAnnotation(ExceptionHandle.class);
                                if (exceptionHandle != null) {
                                    if (StringUtils.isEmpty(exceptionHandle.username())) {
                                        String message = "请在" + name + " \t " + declaredMethod.getName() + " --> " + author + " 方法头的@ExceptionHandle 加上username属性";
                                        notifyWarning(message);
                                    }
                                } else {
                                    String message = "请在" + name + " \t " + declaredMethod.getName() + " --> " + author + " 方法头加上 @ExceptionHandle(username = '')";
                                    notifyWarning(message);
                                }
                            }
                        }
                    }
                }
            }
        }
        return bean;
    }

    private void notifyWarning(String message) {
        if (isException) {
            throw new CheckException(message);
        } else {
            log.error(message);
        }
    }
}